/**
 * 版权所有(C) COVISINT 2015-2025
 * Copyright 2015-2025 COVISINT
 * 创建日期：Jun 26, 20174:52:13 PM
 * 创建人：yyang
 */
package com.wechat.framework.support;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.wechat.framework.constants.EventType;
import com.wechat.framework.constants.MessageType;
import com.wechat.framework.sdk.AesException;
import com.wechat.framework.sdk.WXBizMsgCrypt;
import com.wechat.framework.utils.WechatMessageUtils;

public abstract class WechatFrameworkSupport extends  HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2112896648423255675L;
	
	@RequestMapping(method = {RequestMethod.GET }, produces = "application/json;charset=UTF-8")
	public void valid(HttpServletRequest request, HttpServletResponse response) throws AesException,IOException {
		
		// 解析出url上的参数值如下：
		String sVerifyMsgSig = request.getParameter("msg_signature");
		String sVerifyTimeStamp = request.getParameter("timestamp");
		String sVerifyNonce = request.getParameter("nonce");
		String sVerifyEchoStr = request.getParameter("echostr");
		String sEchoStr = null;
		try {
			WXBizMsgCrypt wxcpt = this.getWXBizMsgCrypt();
			sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,	sVerifyNonce, sVerifyEchoStr);
			if(sEchoStr == null){
				sEchoStr = this.getWechatToken();
			}
			// 验证URL成功，将sEchoStr返回
			ServletOutputStream outputStream = response.getOutputStream();
			this.outputStreamWrite(outputStream,sEchoStr);
		} catch (Exception e) {
			//验证URL失败，错误原因请查看异常
			e.printStackTrace();
		}
	}
	
	/**
	 * 校验信息是否是从微信服务器发过来的。
	 * @param weChat
	 * @param out
	 */
	@RequestMapping(method = {RequestMethod.POST }, produces = "application/xml;charset=UTF-8")
	public void dispose(HttpServletRequest request, HttpServletResponse response) throws AesException,IOException {
		
		// 解析出url上的参数值如下：
		String sVerifyMsgSig = request.getParameter("msg_signature");
		String sVerifyTimeStamp = request.getParameter("timestamp");
		String sVerifyNonce = request.getParameter("nonce");
		
		ServletInputStream inputStream = request.getInputStream();		
		String Post = IOUtils.toString(inputStream, "UTF-8");
		
		String Msg = "";
		WXBizMsgCrypt wxcpt = this.getWXBizMsgCrypt();
		try {
			Msg = wxcpt.DecryptMsg(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, Post);
		} catch (AesException e) {
			e.printStackTrace();
		}
		
		//解析用户请求信息
		Map<String,Map<String,String>> messageMap = this.parseWechatRequestInfo(Msg);
		
		//事件类型
		String msgType = messageMap.keySet().iterator().next();
		
		//取得消息内容		
		Map<String,String> requestInfo = messageMap.get(msgType);
		
		//回复内容
		String respMessage = null;
		
		/**
		 * 判断请求消息类型
		 */
		//事件消息
		if(msgType.equals(MessageType.EVENT)){
			// 事件类型
			String eventType = requestInfo.get("Event");
			
			//成员进入应用的事件推送
			if (eventType.equals(EventType.ENTER_AGENT)) {
				respMessage = this.enterAgentApplicationEvent(requestInfo);
			}
			
			//成员关注[订阅]关注事件
			if (eventType.equals(EventType.SUBSCRIBE)) {
				respMessage = this.subscribeApplicationEvent(requestInfo);
			}
			
			//成员取消[订阅]关注事件
			if (eventType.equals(EventType.UNSUBSCRIBE)) {
				respMessage = this.unSubscribeApplicationEvent(requestInfo);
			}
			
			//上报地理位置事件
			if (eventType.equals(EventType.LOCATION)) {
				respMessage = this.pushLocationEvent(requestInfo);
			}
			
			//点击菜单拉取消息时的事件推送
			if (eventType.equals(EventType.CLICK)) {
				respMessage = this.clickMenuBarEvent(requestInfo);
			}
			
			//点击菜单跳转链接时的事件推送
			if (eventType.equals(EventType.VIEW)) {
				respMessage = this.clickViewEvent(requestInfo);
			}
			
			//扫码推事件的事件推送
			if (eventType.equals(EventType.SCAN_CODE_PUSH)) {
				respMessage = this.scanCodePushEvent(requestInfo);
			}
			
			//扫码推事件且弹出“消息接收中”提示框的事件推送
			if (eventType.equals(EventType.SCAN_CODE_WAITMSG)) {
				respMessage = this.scanCodeWaitMsgEvent(requestInfo);
			}
			
			//弹出系统拍照发图的事件推送
			if (eventType.equals(EventType.PIC_SYSPHOTO)) {
				respMessage = this.picSysphotoEvent(requestInfo);
			}
			
			//弹出拍照或者相册发图的事件推送
			if (eventType.equals(EventType.PIC_PHOTO_OR_ALBUM)) {
				respMessage = this.picPhotoOrAlbumEvent(requestInfo);
			}
			
			//弹出微信相册发图器的事件推送
			if (eventType.equals(EventType.PIC_WEIXIN)) {
				respMessage = this.picWeixinEvent(requestInfo);
			}
			
			//弹出地理位置选择器的事件推送
			if (eventType.equals(EventType.LOCATION_SELECT)) {
				respMessage = this.locationSelectEvent(requestInfo);
			}
			
			//异步任务完成事件推送
			if (eventType.equals(EventType.BATCH_JOB_RESULT)) {
				respMessage = this.batchJobResultEvent(requestInfo);
			}
		}else{
			//这里接收微信推送过来的普通消息
			
			// 文本消息
			if(msgType.equals(MessageType.TEXT)){
				respMessage = this.pushTextMessage(requestInfo);
			}
			// 图片消息
			if(msgType.equals(MessageType.IMAGE)){
				respMessage = this.pushImageMessage(requestInfo);
				this.saveImageMessage(requestInfo);
			}
			// 音频消息
			if(msgType.equals(MessageType.VOICE)){
				respMessage = this.pushVoiceMessage(requestInfo);
			}
			//视频消息
			if(msgType.equals(MessageType.VIDEO)){
				respMessage = this.pushVideoMessage(requestInfo);
			}
			//视频消息
			if(msgType.equals(MessageType.SHORT_VIDEO)){
				respMessage = this.pushShortVideoMessage(requestInfo);
			}
			//地理位置消息
			if(msgType.equals(MessageType.LOCATION)){
				respMessage = this.pushLocationMessage(requestInfo);
			}
			//链接消息
			if(msgType.equals(MessageType.LINK)){
				respMessage = this.pushLinkMessage(requestInfo);
			}
		}
		//返回回应消息
		try {
			if(null != respMessage){
				//加密回复消息
				String encryptMsg = wxcpt.EncryptMsg(respMessage, sVerifyTimeStamp, sVerifyNonce);
				//回复消息返回
				ServletOutputStream outputStream = response.getOutputStream();
				outputStreamWrite(outputStream,encryptMsg);
			}
		} catch (AesException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 解析解密后的微信请求消息类型
	 * @param request
	 * @return
	 */
	private Map<String, Map<String, String>> parseWechatRequestInfo(String request) {
		//存放解析后的请求消息
		Map<String, Map<String, String>> requestMessage = new HashMap<String, Map<String,String>>();
		
		// 调用parseXml方法解析请求消息
		try {
			Map<String, String> requestMap = WechatMessageUtils.parseXml(request);
			
			requestMessage.put(requestMap.get("MsgType"), requestMap);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return requestMessage;
	}
	
	/**
	 * 成员进入应用的事件
	 * @return
	 */
	public abstract String enterAgentApplicationEvent(Map<String,String> requestInfo);
	
	/**
	 * 成员关注[订阅]关注事件
	 * @return
	 */
	public abstract String subscribeApplicationEvent(Map<String,String> requestInfo);
	
	/**
	 * 成员取消[订阅]关注事件
	 * @return
	 */
	public abstract String unSubscribeApplicationEvent(Map<String,String> requestInfo);

	/**
	 * 上报地理位置事件
	 * @return
	 */
	public abstract String pushLocationEvent(Map<String,String> requestInfo);
	
	/**
	 * 点击菜单拉取消息时的事件
	 * @return
	 */
	public abstract String clickMenuBarEvent(Map<String,String> requestInfo);

	/**
	 * 点击菜单跳转链接时的事件
	 * @return
	 */
	public abstract String clickViewEvent(Map<String,String> requestInfo);
	
	/**
	 * 扫码推事件的事件
	 * @return
	 */
	public abstract String scanCodePushEvent(Map<String,String> requestInfo);
	
	/**
	 * 扫码推事件且弹出“消息接收中”提示框的事件
	 * @return
	 */
	public abstract String scanCodeWaitMsgEvent(Map<String,String> requestInfo);

	/**
	 * 弹出系统拍照发图的事件
	 * @return
	 */
	public abstract String picSysphotoEvent(Map<String,String> requestInfo);

	/**
	 * 弹出拍照或者相册发图的事件
	 * @return
	 */
	public abstract String picPhotoOrAlbumEvent(Map<String,String> requestInfo);

	/**
	 * 弹出微信相册发图器的事件
	 * @return
	 */
	public abstract String picWeixinEvent(Map<String,String> requestInfo);

	/**
	 * 弹出地理位置选择器的事件
	 * @return
	 */
	public abstract String locationSelectEvent(Map<String,String> requestInfo);

	/**
	 * 异步任务完成事件
	 * @return
	 */
	public abstract String batchJobResultEvent(Map<String,String> requestInfo);
	
	/**
	 * 请求消息类型：文本
	 * @return
	 */
	public abstract String pushTextMessage(Map<String,String> requestInfo);

	/**
	 * 请求消息类型：图片
	 * @return
	 */
	public abstract String pushImageMessage(Map<String,String> requestInfo);
	
	public abstract void saveImageMessage(Map<String,String> requestInfo);
	
	

	/**
	 * 请求消息类型：音频
	 * @return
	 */
	public abstract String pushVoiceMessage(Map<String,String> requestInfo);

	/**
	 * 请求消息类型：视频
	 * @return
	 */
	public abstract String pushVideoMessage(Map<String,String> requestInfo);

	/**
	 * 请求消息类型：小视频
	 * @return
	 */
	public abstract String pushShortVideoMessage(Map<String,String> requestInfo);

	/**
	 * 请求消息类型：地理位置
	 * @return
	 */
	public abstract String pushLocationMessage(Map<String,String> requestInfo);

	/**
	 * 请求消息类型：链接
	 * @return
	 */
	public abstract String pushLinkMessage(Map<String,String> requestInfo);
	
	/**
	 * 获取微信Token
	 * @return
	 */
	public abstract String getWechatToken();
	
	/**
	 * 获取微信EncodingAeskey
	 * @return
	 */
	public abstract String getWechatEncodingAeskey();
	
	/**
	 * 获取微信CorPid
	 * @return
	 */
	public abstract String getWechatCorPid();
	
	/**
	 * 获取WXBizMsgCrypt
	 * @return
	 */
	private WXBizMsgCrypt getWXBizMsgCrypt(){
		WXBizMsgCrypt wxcpt = null;
		try {
			wxcpt = new WXBizMsgCrypt(this.getWechatToken(),this.getWechatEncodingAeskey(),this.getWechatCorPid());
		} catch (AesException e) {
			e.printStackTrace();
		}
		return wxcpt;
	}
	
	/**
	 * 数据流输出
	 * @param outputStream
	 * @param text
	 * @return
	 */
	private boolean outputStreamWrite(OutputStream outputStream,String text){
		try {
			outputStream.write(text.getBytes("utf-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		return true;
	}
}
